﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Expression.Interactivity;
using System.Windows.Interactivity;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;
using System.Windows.Threading;
using System.Threading;

namespace girapong
{
    public partial class screen : PhoneApplicationPage
    {
        public const int WIDTH = 768;
        public const int HALFWIDTH = 384;
        public const int HEIGHT = 480;
        public const int HALFHEIGHT = 240;

        public bar _barPlayer;//player
        public enemy _barEnemy;//cpu
        public ball _ball;//ball
        protected Accelerometer accelerometer;
        private Vector3 previousVector, currentVector;

        private DispatcherTimer timerEnemy;
        private warning warnings;

        public int turn { get; set; } // 0 player, 1 cpu
        public int userEdge { get; set; }

        public int accelerometerRefreshingTime { get; set; }
        public List<SolidBlock> blockList { get; set; }
        public int currentLevel { get; set; }
        public int playerLifes { get; set; }
        public float enemyStrenght { get; set; }
        public int score { get; set; }
        public int enemy_CurrentSpeed { get; set; }
        public int ball_CurrentSpeed { get; set; }

        public screen() //TOP:1, RIGHT:2, BOTTOM:3, LEFT:4
        {
            InitializeComponent();
            startAccelerometer();
            btnGuardarPuntuacion.Visibility = Visibility.Collapsed;
            btnVolver.Visibility = Visibility.Collapsed;
            Image topImg = new Image();
            topImg.Source = new BitmapImage(new Uri("tope.png", UriKind.RelativeOrAbsolute));
            Image imgAbajo = new Image();
            imgAbajo.Source = new BitmapImage(new Uri("tope.png", UriKind.RelativeOrAbsolute));
            topImg.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            topImg.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            imgAbajo.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            imgAbajo.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            topImg.Margin = new Thickness(0, 0, 0, 0);
            imgAbajo.Margin = new Thickness(0, WIDTH - 5, 0, 0);
            LayoutRoot.Children.Add(topImg);
            LayoutRoot.Children.Add(imgAbajo);
            accelerometer.Start();
            _barPlayer = new bar(System.Windows.Media.Color.FromArgb(255, 0, 0, 255), 0, 0);
            this.LayoutRoot.Children.Add(_barPlayer.rectangle);
            playerLifes = 3;
            enemyStrenght = 1;
            enemy_CurrentSpeed = 7;
            ball_CurrentSpeed = 2;

            _barEnemy = new enemy(System.Windows.Media.Color.FromArgb(255, 255, 0, 0), enemy_CurrentSpeed);
            this.LayoutRoot.Children.Add(_barEnemy._bar.rectangle);
            timerEnemy = new DispatcherTimer();
            timerEnemy.Interval = TimeSpan.FromMilliseconds(1);
            timerEnemy.Tick += new EventHandler(moveEnemy);
            timerEnemy.Start();

            _ball = new ball(this, System.Windows.Media.Color.FromArgb(255, 0, 255, 0), screen.HALFHEIGHT, screen.HALFWIDTH, ball_CurrentSpeed);
            _ball.setSpeed(_ball.speed);
            _ball.playMovement();
            switchContext(0);
            txtFuerza.Text = enemyStrenght.ToString();
            warnings = new warning(this, null);
        }

        public bool startAccelerometer()
        {
            bool ok = false;
            if (!Accelerometer.IsSupported)
            {
                MessageBox.Show("Device doesn´t have accelerometer.");
            }
            else
            {
                try
                {
                    ok = true;
                    accelerometer = new Accelerometer();
                    this.accelerometerRefreshingTime = 88;
                    accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(accelerometerRefreshingTime);
                    accelerometer.CurrentValueChanged += 
                        new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(accelerationDetected);
                }
                catch (Exception)
                {
                    ok = false;
                }
            }
            return ok;
        }

        public void accelerationDetected(object sender, SensorReadingEventArgs<AccelerometerReading> e)
        {
            Dispatcher.BeginInvoke(() => sendReadings(e.SensorReading));
        }
        public void sendReadings(AccelerometerReading reading)
        {
            Vector3 vector = reading.Acceleration;

            int pos = getMobilePosition(vector);
            System.Windows.Shapes.Rectangle rU = _barPlayer.rectangle;
            userEdge = pos;
            double x = 0;
            double y = 0;
            int orientation = 0;

            switch (pos)
            {
                case 1:
                    {
                        orientation = bar.LYING;
                        x = (screen.HEIGHT / 2) + (vector.X * (HALFHEIGHT + rU.Width)) 
                            - rU.Width / 2;
                        y = screen.WIDTH - rU.Height;
                        break;
                    }
                case 2:
                    {
                        orientation = bar.STAND;
                        x = 0;
                        y = HALFWIDTH - (vector.Y * 384); 
                        break;
                    }
                case 3:
                    {
                        orientation = bar.LYING;
                        x = HALFHEIGHT - (vector.X * ((screen.HEIGHT / 2) + rU.Width / 2)) 
                            + rU.Width / 2;
                        y = 0;
                        break;
                    }
                case 4:
                    {
                        orientation = bar.STAND;
                        x = screen.HEIGHT - rU.Width;
                        y = (screen.WIDTH / 2) - (vector.Y * (screen.WIDTH / 2)); 
                        break;
                    }
            }
            _barPlayer.turnBarPerpendicularly(orientation);
            _barPlayer.move(x , y);
            previousVector = vector;
            if (currentVector != null)
            {
                previousVector = currentVector;
            }
            currentVector = vector;
        }

        public int getMobilePosition(Vector3 v)
        {
            if (general.isInterval(v.X, -0.5, 0) || ((v.Y < 0) && general.isInterval(v.X, 0, 0.5))) return 1;
            else if (general.isInterval(v.Y, -0.866, 0) || general.isInterval(v.Y, 0, 0.866))
            {
                if (v.X < 0) return 2;
                return 4;
            }
            else if (general.isInterval(v.X, 0.5, 0) || (general.isInterval(v.Y, 0, -0.5))) return 3;
            return 4;
        }

        public Vector2 vectorDifference()
        {
            Vector3 variacion;
            Vector3.Subtract(ref currentVector, ref previousVector, out variacion);
            return new Vector2(variacion.X, variacion.Y);
        }

        public void pauseAll()
        {
            _ball.stopMovement();
            timerEnemy.Stop();
        }

        public void playAll()
        {
            _ball.playMovement();
            timerEnemy.Start();
        }

        public void killOneLife()
        {
            playerLifes--;
            if (playerLifes == -1)
            {
                accelerometer.Stop();
                pauseAll();
                warn("GAME OVER");
                btnGuardarPuntuacion.Visibility = Visibility.Visible;
                btnVolver.Visibility = Visibility.Visible;
            }
            else
            {
                if (playerLifes == 0) vida1.Visibility = System.Windows.Visibility.Collapsed;
                else if (playerLifes == 1) vida2.Visibility = System.Windows.Visibility.Collapsed;
                else if (playerLifes == 2) vida3.Visibility = System.Windows.Visibility.Collapsed;
                warn("Ouch! Its turn");
            }
        }

        public void addOneScorePoint()
        {
            score++;
            enemyStrenght += 0.1f;
            txtFuerza.Text = enemyStrenght.ToString();
            txtContadorPuntuacion.Text = score.ToString();
            if (score == 5)
            {
                enemy_CurrentSpeed += 4;
                ball_CurrentSpeed += 1;
                _ball.restoreModule = ball_CurrentSpeed;
                currentLevel++;
                switchContext(currentLevel);
                warn("level", currentLevel.ToString());
            }
            else warn("Well!! Pay attention!");
        }
        public void warn(string message)
        {
            pauseAll();
            warnings.setMessage(message);
            warnings.open();
        }
        public void warn(string type, string message)
        {
            warn("new level: " + message);
        }
        public void movePlayer(int pos, double variacionX, double variacionY)
        {
            double x = 0, y = 0;
            switch (pos)
            {
                case 1:
                    {
                        x = _barPlayer.rectangle.Margin.Left + variacionX * screen.HEIGHT; ;                   
                        y = screen.WIDTH - _barPlayer.rectangle.Height;
                        break;
                    }
                case 2:
                    {
                        x = 0;
                        y = _barPlayer.rectangle.Margin.Top - variacionY * screen.WIDTH;
                        break;
                    }
                case 3:
                    {
                        x = _barPlayer.rectangle.Margin.Left - variacionX * screen.HEIGHT;
                        y = 0;
                        break;
                    }
                case 4:
                    {
                        x = screen.HEIGHT - _barPlayer.rectangle.Width;
                        y = _barPlayer.rectangle.Margin.Top - variacionY*screen.WIDTH;
                        break;
                    }
                default:
                    {
                        break;
                    }
            }
            _barPlayer.move(x, y);
        }
        public void switchContext(int nivel)
        {
            SetAppBackground(this.ContentPanel, "nivel0.jpg");
        }
        private static void SetAppBackground(Grid contenedor, string imageName)
        {
            var imageBrush = new ImageBrush
            {
                ImageSource = new BitmapImage(new Uri(imageName, UriKind.Relative))
            };
            contenedor.Background = imageBrush;
        }
        public void moveEnemy(object sender, EventArgs e)
        {
            if (turn == 1)
            {

                int destinyEdge = obtenerBordeMasProximo(_ball);
                System.Windows.Shapes.Rectangle rE = _barEnemy._bar.rectangle;
                System.Windows.Shapes.Ellipse eP = _ball.circle;
                int enemyEdge = getEdgeFromPosition(_barEnemy, rE.Margin.Left, rE.Margin.Top);
                if (enemyEdge == destinyEdge)//same spot both ball and enemy
                {

                    if (((rE.Margin.Top == 0) || (rE.Margin.Top == (screen.WIDTH - rE.Height)))
                        && (rE.Width == bar.WIDTH_DEFAULT))//enemy en top/bottom
                    {
                        _barEnemy.moveAxisXbyBall(_ball, _barEnemy.v);
                    }
                    else if (((rE.Margin.Left == 0) || (rE.Margin.Left == (screen.HEIGHT - rE.Width)))
                        && (rE.Width == bar.HEIGHT_DEFAULT))//enemy in large side
                    {
                        _barEnemy.moveAxisYbyBall(_ball, _barEnemy.v);
                    }
                    else
                    {
                        if ((rE.Margin.Left < 0) && ((rE.Margin.Top + bar.HEIGHT_DEFAULT) > screen.WIDTH))
                        {
                            _barEnemy._bar.turnBarPerpendicularly(bar.LYING);
                            _barEnemy._bar.move(0, screen.WIDTH - bar.HEIGHT_DEFAULT);
                        }
                        else if (((rE.Margin.Left + bar.WIDTH_DEFAULT) > screen.HEIGHT)
                            && ((rE.Margin.Top + bar.WIDTH_DEFAULT) > screen.WIDTH))
                        {
                            _barEnemy._bar.turnBarPerpendicularly(bar.LYING);
                            _barEnemy._bar.move(screen.HEIGHT - bar.WIDTH_DEFAULT, screen.WIDTH - bar.WIDTH_DEFAULT);
                        }
                    }

                }
                else
                {
                    int difX = (enemyEdge % 4) - (destinyEdge % 4);
                    int difY = -1 * difX;
                    if (Math.Abs(difX) == 1) //spot enemy adjacent to ball destiny
                    {
                        if (rE.Margin.Top == 0)
                        {
                            if (rE.Margin.Left == (screen.HEIGHT - bar.HEIGHT_DEFAULT))
                            {
                                _barEnemy.moveAxisYbyAmount(_barEnemy.v);
                            }
                            else
                            {
                                _barEnemy.moveAxisXbyAmount(difY * _barEnemy.v);
                            }
                        }
                        else if (general.isInterval(rE.Margin.Top, screen.WIDTH - rE.Width, screen.WIDTH))
                        {
                            _barEnemy.moveAxisXbyAmount(difX * _barEnemy.v);
                        }
                        else if (rE.Margin.Left == 0)
                        {
                            _barEnemy.moveAxisYbyAmount(difX * _barEnemy.v);
                        }
                        else if (general.isInterval(rE.Margin.Left, screen.HEIGHT - rE.Height, screen.HEIGHT))
                        {
                            _barEnemy.moveAxisYbyAmount(difY * _barEnemy.v);
                        }
                    }
                    else //opposites ubications
                    {
                        if ((enemyEdge == 1) || (enemyEdge == 3))
                        {
                            if (_ball.circle.Margin.Left <= _barEnemy._bar.rectangle.Margin.Left)
                            {
                                _barEnemy.moveAxisXbyBall(_ball, -_barEnemy.v);
                            }
                            else
                            {
                                _barEnemy.moveAxisXbyBall(_ball, _barEnemy.v);
                            }

                        }
                        else
                        {
                            if (_ball.circle.Margin.Top <= _barEnemy._bar.rectangle.Margin.Top)
                            {
                                _barEnemy.moveAxisYbyBall(_ball, _barEnemy.v);
                            }
                            else
                            {
                                _barEnemy.moveAxisYbyBall(_ball, -_barEnemy.v);
                            }
                        }
                    }
                }
            }
        }
        public int getEdgeFromPosition(enemy e, System.Windows.Point p)
        {
            return getEdgeFromPosition(e, p.X, p.Y);
        }
        public int getEdgeFromPosition(enemy e, double x, double y)
        {
            return e.reachedEdge;
        }
        public int obtenerBordeMasProximo(ball _ball)
        {
            double disX = 0;
            double disY = 0;

            Boolean pX = _ball.speed.X > 0;
            Boolean pY = _ball.speed.Y > 0;
            if (pX)
            {
                disX = screen.HEIGHT - (_ball.circle.Margin.Left + _ball.circle.Width);
                if (pY)
                {
                    disY = screen.WIDTH - (_ball.circle.Margin.Top + _ball.circle.Height);
                    if (disX > disY) return 3;
                    else return 2;
                }
                else
                {
                    disY = _ball.circle.Margin.Top;
                    if (disX > disY) return 1;
                    else return 2;
                }
            }
            else
            {
                disX = _ball.circle.Margin.Left;
                if (pY)
                {
                    
                    if (disX > disY) return 3;
                    else return 4;
                }
                else
                {
                    disY = _ball.circle.Margin.Top;
                    if (disX > disY) return 1;
                    else return 4;
                }
            }
        }

        private void btnGuardarPuntuacion_Click(object sender, RoutedEventArgs e)
        {
            btnGuardarPuntuacion.IsEnabled = false;
            ScoresList.newScore(score.ToString(), DateTime.Now.ToString("yyyy/MM/dd:HH:mm"), " 1 VS 1");
        }

        private void btnVolver_Click(object sender, RoutedEventArgs e)
        {
            NavigationService.GoBack();
        }

    }
}